package com.sjf.JavaNIO.Selector;

import org.junit.Test;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

/**
 * @author <huangtang>
 * @since 2022/4/14 15:17
 **/
public class SelectorDemo2 {

    //客户端
    @Test
    public void clientDemo () throws Exception {
        while (true) {
            //1.获取通道，绑定主机和端口号
            SocketChannel socketChannel = SocketChannel.open (new InetSocketAddress ("127.0.0.1" , 8080));
            //2.非阻塞模式
            socketChannel.configureBlocking (false);
            //3.创建buffer
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect (1024);
            //4.写入数据到buffer中
            SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            byteBuffer.put (sdf.format (new Date ()).getBytes (StandardCharsets.UTF_8));
            //5.调buffer的flip方法
            byteBuffer.flip ();
            //6.写入通道
            socketChannel.write (byteBuffer);
            //7.关闭
            socketChannel.close ();

            Thread.sleep (3000);
        }
    }

    /**
     * 先创建ServerSocketChannel注册到选择器中，再用其来获取新得SocketChannel来注册到选择器中
     * 随后遍历SelectionKey来对SocketChannel中得内容作对应数输出打印
     *
     * @throws Exception
     */
    @Test
    public void serverDemo () throws Exception {
        //1.获取通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open ();
        //2.非阻塞模式
        serverSocketChannel.configureBlocking (false);
        //3.创建Buffer
        ByteBuffer buffer = ByteBuffer.allocate (1024);
        //4.绑定端口号
        serverSocketChannel.bind (new InetSocketAddress (8080));
        //5.获取selector选择器
        Selector selector = Selector.open ();
        //6.通道注册到选择器上，进行监听是否 接收 就绪的状态
        serverSocketChannel.register (selector , SelectionKey.OP_ACCEPT);
        //7.选择器进行轮询操作，查看连接选择器的通道的就绪状态，进行后续操作
        while (selector.select () > 0) {
            //说明有就绪的通道操作
            Set<SelectionKey> selectionKeys = selector.selectedKeys ();
            //遍历结合
            Iterator<SelectionKey> selectionKeysIterator = selectionKeys.iterator ();
            while (selectionKeysIterator.hasNext ()) {
                SelectionKey key = selectionKeysIterator.next ();
                //判断key就绪状态操作
                if ( key.isAcceptable () ) {
                    //接收 状态
                    //获取连接
                    SocketChannel accept = serverSocketChannel.accept ();
                    //非阻塞模式
                    accept.configureBlocking (false);
                    //注册
                    accept.register (selector , SelectionKey.OP_READ);
                } else if ( key.isReadable () ) {
                    //可读状态
                    SocketChannel socketChannel = (SocketChannel) key.channel ();

                    //读取数据
                    int length = 0;
                    while ((length = socketChannel.read (buffer)) > 0) {
                        buffer.flip ();
                        System.out.println (new String (buffer.array () , 0 , length));
                        buffer.clear ();
                    }
                }
            }
            selectionKeysIterator.remove ();
        }
    }

    /**
     * 客户端循环输入
     *
     * @param args
     * @throws Exception
     */
    public static void main ( String[] args ) throws Exception {
        //1.获取通道，绑定主机和端口号
        SocketChannel socketChannel = SocketChannel.open (new InetSocketAddress ("127.0.0.1" , 8080));
        //2.非阻塞模式
        socketChannel.configureBlocking (false);
        //3.创建buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate (1024);
        //4.写入数据到buffer中
        Scanner scanner = new Scanner (System.in);
        while (scanner.hasNext ()) {
            String str = scanner.next ();
            byteBuffer.put ((new Date ().toString () + "--->" + str).getBytes (StandardCharsets.UTF_8));
            //5.调buffer的flip方法
            byteBuffer.flip ();
            //6.写入通道
            socketChannel.write (byteBuffer);
            //7.关闭缓冲区
            byteBuffer.clear ();
        }

    }

}
